<?php

declare(strict_types=1);

namespace App\Admin\Service\System;

use App\Admin\Model\System\SystemUser;
use App\Admin\Mapper\System\SystemUserMapper;
use DI\DependencyException;
use DI\NotFoundException;
use Newbie\Abstracts\AbstractService;
use Newbie\exception\NewbieException;
use Newbie\exception\NormalStatusException;
use Newbie\helper\NewbieCaptcha;
use Psr\SimpleCache\InvalidArgumentException;
use Newbie\Cache\Redis;


/**
 * 用户业务
 * Class SystemUserService
 * @package App\system\Service
 */
class SystemUserService extends AbstractService {

    /**
     * @var SystemMenuService
     */
    protected SystemMenuService $sysMenuService;

    /**
     * @var SystemRoleService
     */
    protected SystemRoleService $sysRoleService;

    protected \DI\Container $container;

    /**
     * @var SystemUserMapper
     */
    public $mapper;

    /**
     * SystemUserService constructor.
     * @param SystemUserMapper $mapper
     * @param SystemMenuService $systemMenuService
     * @param SystemRoleService $systemRoleService
     */
    public function __construct (
        SystemUserMapper  $mapper,
        SystemMenuService $systemMenuService,
        SystemRoleService $systemRoleService
    ) {
        $this->mapper         = $mapper;
        $this->sysMenuService = $systemMenuService;
        $this->sysRoleService = $systemRoleService;
        $this->container      = container();
    }

    /**
     * 获取验证码
     * @return array
     * @throws DependencyException
     * @throws NotFoundException
     */
    public function getCaptcha (): array {
        $captcha = new NewbieCaptcha();
        $data    = $captcha->getCaptchaInfo();
        \redis()->set('captcha:' . $data['key'], $data['key'], null, 300);
        return $data;
    }

    public function checkCaptcha ($key, $code) {
        try {
            if (!\redis()->get('captcha:' . $key)) {
                return false;
            }
        } catch (DependencyException|NotFoundException $e) {
            return false;
        }
        return \Tinywan\Captcha\Captcha::check($code, $key);
    }

    /**
     * 获取用户信息
     * @return array
     */
    public function getInfo (): array {
        if (($uid = user()->getId())) {
            return unserialize($this->getCacheInfo((int)$uid));
        }
        throw new NewbieException(t('system.unable_get_userinfo'), 500);
    }

    /**
     * 获取缓存用户信息
     * @param int $id
     */
    protected function getCacheInfo (int $id): string {
        /**@var Redis $cacheService */
        //redis()->del('sysUser:' . $id);
        return redis()->remember('sysUser:' . $id, function () use ($id) {
            /**@var SystemUser $user */
            $user = $this->mapper->getModel()->find($id);
            $user->setHidden(['deleted_at', 'password']);
            $data['user'] = $user->toArray();
            if (user()->isSuperAdmin()) {
                $data['roles']   = ['superAdmin'];
                $data['routers'] = $this->sysMenuService->mapper->getSuperAdminRouters();
                $data['codes']   = ['*'];
            } else {
                $roles           = $this->sysRoleService->mapper->getMenuIdsByRoleIds($user->roles()->pluck('id')->toArray());
                $ids             = $this->filterMenuIds($roles);
                $data['roles']   = $user->roles()->pluck('code')->toArray();
                $data['routers'] = $this->sysMenuService->mapper->getRoutersByIds($ids);
                $data['codes']   = $this->sysMenuService->mapper->getMenuCode($ids);
            }
            return serialize($data);
        }, 3600);
    }

    /**
     * 过滤通过角色查询出来的菜单id列表，并去重
     * @param array $roleData
     * @return array
     */
    protected function filterMenuIds (array &$roleData): array {
        $ids = [];
        foreach ($roleData as $val) {
            foreach ($val['menus'] as $menu) {
                $ids[] = $menu['id'];
            }
        }
        unset($roleData);
        return array_unique($ids);
    }

    /**
     * 新增用户
     * @param array $data
     * @return int
     */
    public function save (array $data): int {
        if ($this->mapper->existsByUsername($data['username'])) {
            throw new NormalStatusException(t('system.username_exists'));
        } else {
            return $this->mapper->save($this->handleData($data));
        }
    }

    /**
     * 更新用户信息
     * @param int $id
     * @param array $data
     * @return bool
     */
    //CacheEvict(prefix: "loginInfo", value: "userId_#{id}")]
    public function update (int $id, array $data): bool {
        if (isset($data['username'])) unset($data['username']);
        if (isset($data['password'])) unset($data['password']);
        $this->clearCache((string)$id);
        return $this->mapper->update($id, $this->handleData($data));
    }

    /**
     * 处理提交数据
     * @param $data
     * @return array
     */
    protected function handleData ($data): array {
        if (!is_array($data['role_ids'])) {
            $data['role_ids'] = explode(',', $data['role_ids']);
        }
        if (($key = array_search(env('ADMIN_ROLE'), $data['role_ids'])) !== false) {
            unset($data['role_ids'][$key]);
        }
        if (!empty($data['post_ids']) && !is_array($data['post_ids'])) {
            $data['post_ids'] = explode(',', $data['post_ids']);
        }
        if (is_array($data['dept_id'])) {
            $data['dept_id'] = array_pop($data['dept_id']);
        }
        return $data;
    }

    /**
     * 获取在线用户
     * @param array $params
     * @return array
     */
    public function getOnlineUserPageList (array $params = []): array {
        $redis   = redis();
        $key     = sprintf('%sToken:*', config('cache.default.prefix', ''));
        $users   = $redis->keys($key);
        $userIds = [];

        foreach ($users as $user) {
            if (preg_match("/{$key}(\d+)$/", $user, $match) && isset($match[1])) {
                $userIds[] = $match[1];
            }
        }

        if (empty($userIds)) {
            return [];
        }

        return $this->getPageList(array_merge(['showDept' => 1, 'userIds' => $userIds], $params));
    }

    /**
     * 删除用户
     * @param string $ids
     * @return bool
     */
    public function delete (string $ids): bool {
        if (!empty($ids)) {
            $userIds = explode(',', $ids);
            if (($key = array_search(env('SUPER_ADMIN'), $userIds)) !== false) {
                unset($userIds[$key]);
            }

            return $this->mapper->delete($userIds);
        }

        return false;
    }

    /**
     * 真实删除用户
     * @param string $ids
     * @return bool
     */
    public function realDelete (string $ids): bool {
        if (!empty($ids)) {
            $userIds = explode(',', $ids);
            if (($key = array_search(env('SUPER_ADMIN'), $userIds)) !== false) {
                unset($userIds[$key]);
            }

            return $this->mapper->realDelete($userIds);
        }

        return false;
    }

    /**
     * 强制下线用户
     * @param string $id
     * @return bool
     * @throws InvalidArgumentException
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    public function kickUser (string $id): bool {
        $redis = redis();
        $key   = sprintf("Token:%s", $id);
        if ($redis->exists($key)) {
            $redis->del($key);
        }
        return true;
    }

    /**
     * 初始化用户密码
     * @param int $id
     * @param string $password
     * @return bool
     */
    public function initUserPassword (int $id, string $password = '123456'): bool {
        return $this->mapper->initUserPassword($id, $password);
    }

    /**
     * 清除用户缓存
     * @param string $id
     * @return bool
     * @throws DependencyException
     * @throws NotFoundException
     */
    public function clearCache (string $id): bool {
        /**@var Redis $redis */
        $redis = $this->container->get(Redis::class);
        $redis->del("sysUser:{$id}");
        $redis->del("loginInfo:userId_{$id}");
        return true;
    }

    /**
     * 设置用户首页
     * @param array $params
     * @return bool
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    public function setHomePage (array $params): bool {
        $res = ($this->mapper->getModel())::query()
                ->where('id', $params['id'])
                ->update(['dashboard' => $params['dashboard']]) > 0;
        $this->clearCache((string)$params['id']);
        return $res;
    }

    /**
     * 用户更新个人资料
     * @param array $params
     * @return bool
     * @throws DependencyException
     * @throws NotFoundException
     */
    public function updateInfo (array $params): bool {
        if (!isset($params['id'])) {
            return false;
        }

        $model = $this->mapper->getModel()::find($params['id']);
        unset($params['id'], $params['password'], $params['username'], $params['user_type']);
        foreach ($params as $key => $param) {
            $model[$key] = $param;
        }

        $this->clearCache((string)$model['id']);
        return $model->save();
    }

    /**
     * 用户修改密码
     * @param array $params
     * @return bool
     */
    public function modifyPassword (array $params): bool {
        return $this->mapper->initUserPassword((int)user()->getId(), $params['newPassword']);
    }
}